package com.niit.mall.mall.gateway.routers;


import cn.hutool.json.JSONUtil;
import com.alibaba.cloud.nacos.NacosConfigManager;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import com.niit.mall.common.utils.CollUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

import javax.annotation.PostConstruct;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Executor;

/**
 * @BelongsProject: pardo_mall_backend
 * @BelongsPackage: com.niit.mall.mall.gateway.routers
 * @Author: ChuXuan
 * @CreateTime: 2025-06-06  09:15
 * @Description: 动态路由加载器
 * @Version: 1.0
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class DynamicRouteLoader {
	
	private final RouteDefinitionWriter writer;
	private final NacosConfigManager nacosConfigManager;
	
	// 路由配置文件的id和分组
	private final String dataId = "gateway-routes.json";
	private final String group = "DEFAULT_GROUP";
	// 保存更新过的路由id
	private final Set<String> routeIds = new HashSet<>();
	
	@PostConstruct
	public void initRouteConfigListener() throws NacosException {
		// 1.注册监听器并首次拉取配置
		String configInfo = nacosConfigManager.getConfigService()
				                    .getConfigAndSignListener(dataId, group, 5000, new Listener() {
					                    @Override
					                    public Executor getExecutor() {
						                    return null;
					                    }
					                    
					                    @Override
					                    public void receiveConfigInfo(String configInfo) {
						                    updateConfigInfo(configInfo);
					                    }
				                    });
		// 2.首次启动时，更新一次配置
		updateConfigInfo(configInfo);
	}
	
	private void updateConfigInfo(String configInfo) {
		log.debug("监听到路由配置变更，{}", configInfo);
		// 1.反序列化
		List<RouteDefinition> routeDefinitions = JSONUtil.toList(configInfo, RouteDefinition.class);
		// 2.更新前先清空旧路由
		// 2.1.清除旧路由
		for (String routeId : routeIds) {
			writer.delete(Mono.just(routeId)).subscribe();
		}
		routeIds.clear();
		// 2.2.判断是否有新的路由要更新
		if (CollUtils.isEmpty(routeDefinitions)) {
			// 无新路由配置，直接结束
			return;
		}
		// 3.更新路由
		routeDefinitions.forEach(routeDefinition -> {
			// 3.1.更新路由
			writer.save(Mono.just(routeDefinition)).subscribe();
			// 3.2.记录路由id，方便将来删除
			routeIds.add(routeDefinition.getId());
		});
	}
}

